package com.mars.pay.service;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.mars.pay.config.WechatPayConfig;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;
import org.springframework.core.io.ClassPathResource;
import cn.hutool.core.util.IdUtil;

import java.io.ByteArrayInputStream;
import java.security.PrivateKey;
import java.security.Signature;
import java.nio.charset.StandardCharsets;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class WechatPayService {

    private final WechatPayConfig wechatPayConfig;
    private final CloseableHttpClient wechatPayClient;

    /**
     * 小程序支付
     */
    public Map<String, String> miniAppPay(String orderNo, String description, Integer totalFee, String openid) throws IOException {
        JSONObject reqData = new JSONObject();
        reqData.put("appid", wechatPayConfig.getAppId());
        reqData.put("mchid", wechatPayConfig.getMchId());
        reqData.put("description", description);
        reqData.put("out_trade_no", orderNo);
        reqData.put("notify_url", wechatPayConfig.getNotifyUrl());

        JSONObject amount = new JSONObject();
        amount.put("total", totalFee);
        amount.put("currency", "CNY");
        reqData.put("amount", amount);

        JSONObject payer = new JSONObject();
        payer.put("openid", openid);
        reqData.put("payer", payer);

        String url = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
        String response = executePost(url, reqData.toString());
        log.info("微信支付下单响应: {}", response);

        JSONObject responseData = JSON.parseObject(response);
        String prepayId = responseData.getString("prepay_id");
        log.info("获取到prepay_id: {}", prepayId);

        return buildMiniAppPayParams(prepayId);
    }

    /**
     * 扫码支付
     */
    public String nativePay(String orderNo, String description, Integer totalFee) throws IOException {
        JSONObject reqData = new JSONObject();
        reqData.put("appid", wechatPayConfig.getAppId());
        reqData.put("mchid", wechatPayConfig.getMchId());
        reqData.put("description", description);
        reqData.put("out_trade_no", orderNo);
        reqData.put("notify_url", wechatPayConfig.getNotifyUrl());

        JSONObject amount = new JSONObject();
        amount.put("total", totalFee);
        amount.put("currency", "CNY");
        reqData.put("amount", amount);

        String url = "https://api.mch.weixin.qq.com/v3/pay/transactions/native";
        String response = executePost(url, reqData.toString());

        JSONObject responseData = JSON.parseObject(response);
        return responseData.getString("code_url");
    }

    /**
     * H5支付
     */
    public String h5Pay(String orderNo, String description, Integer totalFee) throws IOException {
        JSONObject reqData = new JSONObject();
        reqData.put("appid", wechatPayConfig.getAppId());
        reqData.put("mchid", wechatPayConfig.getMchId());
        reqData.put("description", description);
        reqData.put("out_trade_no", orderNo);
        reqData.put("notify_url", wechatPayConfig.getNotifyUrl());

        JSONObject amount = new JSONObject();
        amount.put("total", totalFee);
        amount.put("currency", "CNY");
        reqData.put("amount", amount);

        JSONObject sceneInfo = new JSONObject();
        JSONObject h5Info = new JSONObject();
        h5Info.put("type", "Wap");
        sceneInfo.put("h5_info", h5Info);
        reqData.put("scene_info", sceneInfo);

        String url = "https://api.mch.weixin.qq.com/v3/pay/transactions/h5";
        String response = executePost(url, reqData.toString());

        JSONObject responseData = JSON.parseObject(response);
        return responseData.getString("h5_url");
    }

    /**
     * 构建小程序调起支付参数
     */
    private Map<String, String> buildMiniAppPayParams(String prepayId) {
        Map<String, String> map = new HashMap<>();
        // 注意这里使用appId，不要用appid
        map.put("appId", wechatPayConfig.getAppId());
        // 时间戳需要秒级
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        String nonceStr = IdUtil.simpleUUID();
        String packageStr = "prepay_id=" + prepayId;

        map.put("timeStamp", timestamp);
        map.put("nonceStr", nonceStr);
        map.put("package", packageStr);
        map.put("signType", "RSA");

        // 签名串按照文档拼接
        String message = wechatPayConfig.getAppId() + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + packageStr + "\n";

        log.info("签名原文: {}", message);

        try {
            PrivateKey privateKey1 = PemUtil
                    .loadPrivateKey(new ByteArrayInputStream(wechatPayConfig.getPrivateKey().getBytes(StandardCharsets.UTF_8)));

            // 初始化签名对象
            Signature signature = Signature.getInstance("SHA256withRSA");
            signature.initSign(privateKey1);
            signature.update(message.getBytes(StandardCharsets.UTF_8));

            // 计算签名
            byte[] signBytes = signature.sign();
            // Base64编码
            String paySign = java.util.Base64.getEncoder().encodeToString(signBytes);
            map.put("paySign", paySign);

            log.info("生成支付参数: {}", map);
            return map;
        } catch (Exception e) {
            log.error("生成支付签名异常", e);
            throw new RuntimeException("生成支付签名异常", e);
        }
    }

    /**
     * 执行HTTP POST请求
     */
    private String executePost(String url, String requestStr) throws IOException {
        HttpPost httpPost = new HttpPost(url);
        httpPost.addHeader("Accept", "application/json");
        httpPost.addHeader("Content-Type", "application/json");

        StringEntity entity = new StringEntity(requestStr, "UTF-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);

        try (CloseableHttpResponse response = wechatPayClient.execute(httpPost)) {
            String result = EntityUtils.toString(response.getEntity());
            log.info("POST请求响应: {}", result);
            return result;
        }
    }
}
